home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / DELPHI32 / DEBUG / STAKWK10 / STAKWK10.ZIP / STAKLOW.PAS < prev    next >
Pascal/Delphi Source File  |  1996-05-10  |  6KB  |  258 lines

  1. unit StakLow;
  2. { Low level Delphi 2.0 debugger fix unit.  Copyright (c) 1996, D.J. Murdoch }
  3. { THIS VERSION IS NOT FOR DISTRIBUTION!!!! }
  4. {$D-  We don't want this code to be reported }
  5. {$OPTIMIZATION off } { And we don't want it optimized } 
  6. interface
  7.  
  8. uses classes,sysutils;
  9.  
  10. type
  11.   EDebug = class(Exception);
  12.  
  13.   TRange = class
  14.     start, stop : integer;
  15.   end;
  16.  
  17.   TRangeList = class(TList)
  18.     { This is a list of ranges of addresses to report }
  19.     destructor destroy; override;
  20.  
  21.     procedure FreeAll;
  22.     { Frees all the ranges }
  23.  
  24.     function InRange(target:pointer):boolean;
  25.     { Checks whether start <= target <= stop
  26.       for some entry in the list }
  27.  
  28.     procedure ReadMapFile(filename:string);
  29.     { Reads a .MAP file to initialize }
  30.  
  31.     procedure HandleException(Sender: TObject; E: Exception);
  32.     { Possible handler for Application.OnException }
  33.   end;
  34.  
  35. procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer);
  36. { Handler to use in place of ExceptProc }
  37.  
  38. procedure WalkStack;
  39. { Walks through the stack, triggering an EDebug exception at everything that
  40.   looks as though it might be a return address }
  41.  
  42. type
  43.   TContinueFunc = function:boolean;
  44.   TWarnProc = procedure;
  45. var
  46.   StackWalker : TRangeList;
  47.   FoundMap : boolean;
  48.   StopWalker : boolean;
  49.   WalkerActive : boolean;
  50.   ContinueFunc : TContinueFunc;
  51.   Walking : boolean;
  52.  
  53. implementation
  54.  
  55. procedure TRangeList.FreeAll;
  56. var
  57.   i : integer;
  58. begin
  59.   for i:=0 to pred(count) do
  60.     TRange(Items[i]).Free;
  61.   Count := 0;
  62. end;
  63.  
  64. destructor TRangeList.Destroy;
  65. begin
  66.   FreeAll;
  67.   inherited;
  68. end;
  69.  
  70. function TRangeList.InRange(target:pointer):boolean;
  71. var
  72.   i : Integer;
  73. begin
  74.   result := false;
  75.   for i:=0 to pred(count) do
  76.     with TRange(Items[i]) do
  77.       if (start <= integer(target)) and (integer(target) <= stop) then
  78.       begin
  79.         result := true;
  80.         exit;
  81.       end;
  82. end;
  83.  
  84. procedure TRangeList.ReadMapFile(filename:string);
  85. var
  86.   map : textfile;
  87.   line : string;
  88.   range : TRange;
  89.   mapshift : integer;
  90.   buffer : array[1..8192] of byte;
  91. begin
  92.   mapshift := 0;
  93.   FreeAll;
  94.   assignfile(map,filename);
  95.   settextbuf(map,buffer);
  96.   {$i-}
  97.   reset(map);
  98.   {$i+}
  99.   if ioresult = 0 then
  100.   begin
  101.     while not eof(map) do
  102.     begin
  103.       readln(map,line);
  104.       if pos('Publics by Value',line) > 0 then
  105.         break;
  106.     end;
  107.     while not eof(map) do
  108.     begin
  109.       readln(map,line);
  110.       if pos('TextStart',line) > 0 then
  111.       begin
  112.         mapshift := integer(@TextStart) - StrToInt('$'+copy(line,7,8));
  113.         break;
  114.       end;
  115.     end;
  116.     while not eof(map) do
  117.     begin
  118.       readln(map,line);
  119.       if pos('Line numbers for ',line) > 0 then
  120.       begin
  121.         range := TRange.Create;
  122.         readln(map,line);
  123.         if line = '' then
  124.           readln(map,line);
  125.         range.start := mapshift + StrToInt('$'+copy(line,13,8));
  126.         range.stop := mapshift + StrToInt('$'+copy(line,length(line)-7,8));
  127.         while not eof(map) do
  128.         begin
  129.           readln(map,line);
  130.           if line = '' then
  131.             break;
  132.           range.stop := mapshift + StrToInt('$'+copy(line,length(line)-7,8));
  133.         end;
  134.         Add(range);
  135.       end;
  136.     end;
  137.     closefile(map);
  138.   end;
  139.   if count = 0 then
  140.   begin
  141.     FoundMap := false;
  142.     range := TRange.create;
  143.     range.start := integer(@TextStart);
  144.     range.stop := integer(@HeapAllocFlags);
  145.     Add(range);
  146.   end
  147.   else
  148.     FoundMap := true;
  149. end;
  150.  
  151. procedure WalkStack;
  152. var
  153.   target : pointer;
  154.   hitnum : integer;
  155.   saveclass : TClass;
  156.   p,stackstart,stacktop : ^pointer;
  157. begin
  158.   if walking then
  159.     exit;
  160.   stopwalker := false;
  161.   walking := true;
  162.   saveclass := ExceptionClass;
  163.   asm
  164.     mov stackstart,esp
  165.   end;
  166.   ExceptionClass := Nil;  { Run until we hit the top of the stack, but don't
  167.                             let the debugger know about it. }
  168.   p := stackstart;
  169.   try
  170.     repeat
  171.       target := p^;
  172.       inc(p);
  173.     until false;
  174.   except
  175.     stacktop := p;
  176.   end;
  177.   ExceptionClass := SaveClass;
  178.  
  179.   hitnum := 0;
  180.   p := stackstart;
  181.   try
  182.     while (not StopWalker) and (integer(p) < integer(stacktop)) do
  183.     begin
  184.       ExceptionClass := Nil;
  185.       target := p^;
  186.       ExceptionClass := saveclass;
  187.       if stackwalker.inrange(target) then
  188.       begin
  189.         if assigned(ContinueFunc) and not ContinueFunc then
  190.           break;
  191.         inc(hitnum);
  192.         if hitnum > 0 then
  193.           try
  194.             raise edebug.create(format('Hit number %d at %x, %d%% done',
  195.                                        [hitnum,integer(target),
  196.                                         ((integer(p)-integer(stackstart))*100) div
  197.                                          (integer(stacktop)-integer(stackstart))]))
  198.                   at target;
  199.           except
  200.           end;
  201.       end;
  202.       inc(p);
  203.     end;
  204.   except
  205.   end;
  206.   walking := false;
  207. end;
  208.  
  209. type
  210.   thandler = procedure(ExceptObject: TObject; ExceptAddr: Pointer);
  211. var
  212.   saveexcept : thandler;
  213.  
  214. procedure fpuinit; assembler;
  215. const cwDefault: Word = $1332 { $133F};
  216. begin
  217.   asm
  218.         FNINIT
  219.         FWAIT
  220.         FLDCW   cwDefault
  221.   end;
  222. end;
  223.  
  224. procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer);
  225. begin
  226.   {  fpuinit; }
  227.   if WalkerActive then
  228.     WalkStack;
  229.   saveexcept(ExceptObject,ExceptAddr);
  230. end;
  231.  
  232. procedure TRangeList.HandleException(Sender: TObject; E: Exception);
  233. begin
  234. {  fpuinit; }
  235.   ShowException(E,ExceptAddr);
  236.   if WalkerActive then
  237.     WalkStack;
  238. end;
  239.  
  240. initialization
  241.   saveexcept := THandler(ExceptProc);
  242.   if debughook <> 0 then
  243.   begin
  244.     stackwalker := TRangeList.Create;
  245.     FoundMap := false;
  246.     stackwalker.readmapfile(ChangeFileExt(paramstr(0),'.map'));
  247.     ExceptProc := @ExceptHandler;
  248.     ContinueFunc := nil;
  249.     WalkerActive := true;
  250.     Walking := false;
  251.   end
  252.   else
  253.     StackWalker := Nil;
  254. finalization
  255.   ExceptProc := @saveexcept;
  256.   stackwalker.free;
  257. end.
  258.